home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 111_01 / xpr.c < prev   
Text File  |  1985-08-19  |  8KB  |  395 lines

  1. /*
  2. HEADER:        ;
  3. TITLE:        Transfer via punch and reader;
  4. VERSION:    1.0;
  5. DATE:        12/11/1981;
  6.  
  7. DESCRIPTION:    "Transfers files between CP/M systems, through
  8.         BDOS, using punch and reader.";
  9.  
  10. KEYWORDS:    Communication, transfer, utility;
  11. SYSTEM:        CP/M-80;
  12. FILENAME:    XPR.C;
  13. AUTHORS:    Ward Christensen;
  14. COMPILERS:    BDS C;
  15. */
  16. /*******************************************************************
  17.  
  18. Version 1.0, 12/11/1982:
  19.         Ward Christensen
  20.  
  21. DEPENDENCIES:    S T A R T   T H E   S E N D I N G   P R O G R A M   F I R S T ,
  22.         as there is no way to "time out", and recover, since
  23.         RDR/PUN have no "status test" ability.
  24.  
  25. EXECUTION:    On the sending/punching machine, type:
  26.  
  27.         xpr s filename...
  28.     or    xpr p filename...    Sends (Punches) a file to PUN
  29.  
  30.         On the receiving/reading machine, type:
  31.  
  32.         xpr r filename...    Receive (Reads) via RDR
  33.  
  34. N O T E :    "..." means multiple filenames may be specified:
  35.         xpr s b:othello.c a:stat.com b:foo.c
  36.  
  37. DOCUMENTATION:    Protocol consists of:
  38.  
  39.     1.    Receiver sends SYNC byte to cause sender to start.
  40.  
  41.     2.    Each sector is sent as:
  42.  
  43.         SOH,SECT,<-- 128 bytes data -->,CKSUM
  44.  
  45.         Cksum is simply the 16-bit sum of the data characters,
  46.         sent as:
  47.             (Cksum & 0xff)+(Cksum/256)
  48.         in order to go over an 8-bit channel.
  49.  
  50.     3.    RESPONSE is either ACK or NAK.
  51.  
  52.     4.    EOT sent at end of file.
  53.  
  54.     5.    SOH, ACK, NAK, and EOT are always sent as-is.
  55.         When in 7-bit mode, all other data (sector #, data) is
  56.         sent as two hex-ASCII characters.
  57.  
  58.  
  59.         function directory with their line #'s
  60.  
  61. physout() 96    physin() 103    main() 112    option() 131    errexit() 156
  62. dofile() 169    sendfile() 184    sendsec() 215    recvfile() 246    recvsec() 276
  63. rdrchr() 314    logicalin() 323    hex() 332    punchr() 340    nibble() 353
  64. abort() 363    testname() 375
  65.  
  66. ****************************************************************************/
  67.  
  68. #include <bdscio.h>
  69. #define    SECSIZ    128
  70. #define    SYNC    0x27
  71. #define    SOH    1
  72. #define    ACK    6
  73. #define    NAK    0x18
  74. #define    EOT    4
  75. #define    CANCEL    'X'
  76. #define    CPMRDR    3
  77. #define    CPMPUN    4
  78.  
  79. /*        GLOBALS        (start with capital letters)
  80. */
  81.     char    Fbuf[BUFSIZ],    /* input/output buff        */
  82.         Tbuf[SECSIZ],    /* xmit/recv buffer        */
  83.         *Bufptr,    /* Pointer into Fbuf        */
  84.         Send,        /* true if sending file        */
  85.         Recv,        /* true if receiving file    */
  86.         Sevenbit,    /* true if 7-bit transfer    */
  87.         C;        /* general single char        */
  88.     int    Filenum,    /* argv index for next file     */
  89.         Secno,        /* sector to send        */
  90.         Nerrs,        /* number of errs        */
  91.         Toterrs,    /* Total number of errors    */
  92.         Nread,        /* # sectors read        */
  93.         Fd,        /* File Descriptor        */
  94.         I;        /* general index        */
  95.     Unsigned Cksum;        /* block transfer cksum     */
  96.  
  97.  
  98. /*    ================================================
  99.     >>> These are the physical character drivers <<<
  100.         The rest of the program is all "logical I/O "
  101. */
  102.  
  103. /*    --- physical char output ---
  104. */
  105. physout(chr)
  106. char    chr;
  107. {    bdos(CPMPUN,chr);
  108. }    
  109.  
  110. /*    --- physical char input ---
  111. */
  112. physin()
  113. {    return(bdos(CPMRDR,0));
  114. }
  115.  
  116. /*        >>> End of physical I/O <<<
  117.         ===========================
  118.  
  119.     --- M A I N ---
  120. */
  121. main(argc,argv)
  122. int argc; char **argv;
  123. {
  124.     Sevenbit=
  125.     Toterrs=
  126.     Send=
  127.     Recv=0;
  128.     Filenum=2;                /* next argv name    */
  129.     option(argc,argv);            /* validate option    */
  130.     while ((argc) > Filenum)        /* while more files    */
  131.         dofile(argv[Filenum++]);    /* do one file        */
  132.     puts("Processing completed, ");
  133.     printf("%d file(s), %d errors\n",Filenum-2,Toterrs);
  134.     exit(0);
  135. }
  136.  
  137. /*
  138.     --- Process the option byte ---
  139. */
  140. option(argc,argv)
  141. int    argc;
  142. char    **argv;
  143. {    char c;
  144.     if (argc < 3)                /* option + 1 or more files? */
  145.         errexit();
  146.     if (argv[1][1]=='7')
  147.         Sevenbit = 1;            /* doing 7-bit transfer    */
  148.     c=argv[1][0];                /* get option        */
  149.     switch(c)                /* test it        */
  150.     {    case 'S':            /* Send            */
  151.         case 'P':            /* or Punch?        */
  152.             Send = 1;        /*     show sending    */
  153.             return(0);
  154.         case 'R':            /* Receive/read?    */
  155.             Recv = 1;        /*    show receiving    */
  156.             return(0);
  157.         default:
  158.             errexit();        /* otherwise, error exit*/
  159.     }
  160. }    /* end of "option" */
  161.  
  162. /*
  163.     --- exit with usage explanation message ---
  164. */
  165. errexit()
  166. {    puts("XPR by Ward Christensen\n");
  167.     puts("CP/M Xfer via Punch and Rdr\n\n");    
  168.     puts("    Invalid option.  Format is:\n\
  169.     xpr s filename1 [filename2...]    on the sending machine\n\
  170.     xpr r filename1 [filename2...]    on the receiving machine\n\n\
  171.     s7 or r7 may be used for 7-bit tranfers (both ends must agree)\n");
  172.     exit(999);
  173. }
  174.  
  175. /*
  176.     --- Do a file ---
  177. */
  178. dofile(file)
  179. char    *file;
  180. {    if (testname(file))
  181.     {    puts("No ambiguous files allowed\n");
  182.         errexit();
  183.     }
  184.     if (Send)
  185.         Sendfile(file);
  186.     if (Recv)
  187.         Recvfile(file);
  188. }
  189.  
  190. /*
  191.     --- send a file ---
  192. */
  193. sendfile(file)
  194. char    *file;
  195. {    if ((Fd=open(file,0))==ERROR)        /* open for input    */
  196.     {    printf("cannot open: %s\n",file);
  197.     exit();
  198.     }
  199.     printf("Sending file %s ",file);
  200.  
  201.     C=physin() & 0x7f;            /* get sync byte    */
  202.     if (C != SYNC)
  203.     {    printf("%x received, not SYNC; aborting\n",C);
  204.         exit(0);
  205.     }
  206.     puts("Sync received\n");
  207.     Secno=1;
  208.     while (0< (Nread = read(Fd,Fbuf,BUFSIZ/SECSIZ)))
  209.     {
  210.         Bufptr=Fbuf;            /* init pointer        */
  211.         while(Nread--)
  212.             sendsec();
  213.     }
  214.     physout(EOT);
  215.     if (Nread == ERROR)
  216.         abort("Read error\n");
  217.     close(file);
  218.     puts("\n");
  219. }
  220.  
  221. /*
  222.     --- Send a sector ---
  223. */
  224. sendsec()
  225. {    char *ptr;
  226.     Nerrs=0;
  227.     while(1)
  228.     {    ptr=Bufptr;
  229.         Cksum=0;
  230.         putchar('.');
  231.         physout(SOH);            /* send header    */
  232.         punchr(Secno);            /*     secno    */
  233.         for (I=0;I<128;++I)
  234.         {    punchr(*ptr);        /*    data    */
  235.             Cksum+=*ptr++;
  236.         }
  237.  
  238.         punchr((Cksum & 0xff)+(Cksum/256)); /*    cksum     */
  239.  
  240.         if ((C=rdrchr())==ACK)
  241.         {    Secno=(++Secno & 0x0f);
  242.             Bufptr+=128;
  243.             return(0);
  244.         }
  245.         ++Toterrs;
  246.         printf("0x%x rcd, not ACK\n",C);
  247.         if (++Nerrs == 10)
  248.             abort("Too many errors\n");
  249.     }
  250. }
  251.  
  252. /*
  253.     --- receive a file ---
  254. */
  255. recvfile(file)
  256. char    *file;
  257. {    int    count;
  258.     if ((Fd=creat(file))==ERROR)        /* delete, open for out    */
  259.     {    printf("cannot make: %s\n",file);
  260.     exit();
  261.     }
  262.     printf("Receiving file %s\n",file);
  263.     physout(SYNC);                /* Sync transmitter    */
  264.     Secno=1;
  265.     Bufptr=Fbuf;
  266.     count=0;
  267.     while (recvsec())            /* get a block        */
  268.     {    if (++count==(BUFSIZ/SECSIZ))    /* buffer full        */
  269.         {    if (write(Fd,Fbuf,count)!=count)
  270.                 abort("Write error\n");
  271.             Bufptr=Fbuf;
  272.             count=0;
  273.         }
  274.         punchr(ACK);
  275.     }
  276.     if (count > 0)
  277.         write(Fd,Fbuf,count);
  278.     close(Fd);
  279.     puts("\n");
  280. }
  281.  
  282. /*
  283.     --- receive a sector ---
  284. */
  285. recvsec()
  286. {    char *ptr;
  287.     Nerrs=0;
  288.     while(1)
  289.     {    ptr=Bufptr;
  290.         Cksum=0;
  291.         C=logicalin();
  292.         if (C==CANCEL)
  293.             abort("Program cancelled from other end\n");
  294.         if (C==EOT)
  295.             return(0);
  296.         if (C!=SOH)
  297.             abort("SOH not received\n");
  298.         if (rdrchr()!=Secno)
  299.             abort("Invalid sector # received\n");
  300.         for (I=0;I<128;++I)
  301.         {    *ptr=rdrchr();
  302.             Cksum+=*ptr++;
  303.         }
  304.         C=rdrchr();
  305.         Cksum=(((Cksum & 0xff)+(Cksum/256))&0xff);
  306.         if (Cksum==C)                /* valid cksum?    */
  307.         {    Secno=(++Secno & 0x0f);
  308.             Bufptr+=128;
  309.             putchar('.');
  310.             return(1);
  311.         }
  312.         ++Toterrs;
  313.         punchr(NAK);
  314.         puts("Cksum\n");
  315.         if (++Nerrs == 10)
  316.             abort("Too many errors\n");
  317.     }
  318. }
  319.  
  320. /*
  321.     --- Get a char from the reader ---
  322. */
  323. rdrchr()
  324. {    if (Sevenbit)
  325.         return (16*hex(logicalin())+hex(logicalin()));
  326.     else    return(logicalin());
  327. }
  328.  
  329. /*
  330.     --- logical char input ---
  331. */
  332. logicalin()
  333. {    if (Sevenbit)
  334.         return(physin() & 0x7f);
  335.     else    return(physin());
  336. }
  337.  
  338. /*
  339.     --- printable hex to binary conversion, 1 nibble ---
  340. */
  341. hex(nib)
  342. char    nib;
  343. {    return( (nib>'9') ? nib-'7' : nib-'0' );
  344. }
  345.  
  346. /*
  347.     --- put a char to the punch ---
  348. */
  349. punchr(chr)
  350. char    chr;
  351. {    if (Sevenbit)
  352.     {    physout(nibble(chr / 16));
  353.         physout(nibble(chr));
  354.     }
  355.     else    physout(chr);
  356. }
  357.  
  358.  
  359. /*
  360.     --- convert a char to a nibble in printable hex --
  361. */
  362. nibble(chr)
  363. char    chr;
  364. {    chr=chr & 0x0f;
  365.     return( (chr<10) ? '0'+chr : '7'+chr );
  366. }
  367.  
  368.  
  369. /*
  370.     --- Abort transmitting ---
  371. */
  372. abort(msg)
  373. char    *msg;
  374. {    puts(msg);
  375.     puts(">> aborting <<\n");
  376.     printf("C=%x\n",C);
  377.     punchr(CANCEL);
  378.     exit();
  379. }
  380.  
  381. /*
  382.     --- test that a filename doesn't contain "?"s ---
  383. */
  384. testname(str)
  385. char    *str;
  386. {    char *local,c;
  387.     local=str;
  388.     while(*local)            /* exit on \0    */
  389.     if((c=*local++)== '?'        /* is it "?"    */
  390.           || c == '*')        /* or is it "*"    */
  391.         return(1);            /* ret if s